<template>
  <div id="scheduler">
    <el-card class="process-card">
      <el-row :gutter="25">
        <el-col :span="7">
          <div class="flex">
            <el-button
              type="primary"
              icon="el-icon-plus"
              @click="randomCreateProcess()"
              class="mr-3 flex-shrink"
              >随机添加</el-button
            >
            <el-select
              v-model="value"
              placeholder="请选择"
              class="flex-shrink-0"
            >
              <el-option
                v-for="item in options"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              >
              </el-option>
            </el-select>
          </div>
        </el-col>
      </el-row>
    </el-card>

    <div v-show="value == 0">
      <process-table
        :process_queue="ready_queue"
        header="就绪队列"
        badge_type="primary"
        :need_num="true"
      ></process-table>
    </div>

    <div v-show="value == 1">
      <process-table
        :process_queue="first_queue"
        header="第一队列"
        badge_type="primary"
        :need_num="true"
      ></process-table>
      <process-table
        :process_queue="second_queue"
        header="第二队列"
        badge_type="primary"
        :need_num="true"
      ></process-table>
      <process-table
        :process_queue="third_queue"
        header="第三队列"
        badge_type="primary"
        :need_num="true"
      ></process-table>
    </div>

    <div v-show="value == 2">
      <process-table
        :process_queue="ready_queue"
        header="就绪队列"
        badge_type="primary"
        :need_ratio="true"
      ></process-table>
    </div>
    <process-table
      :process_queue="over_queue"
      header="终止队列"
      badge_type="danger"
    ></process-table>
  </div>
</template>

<script>
import { ElMessage } from 'element-plus'
import ProcessTable from '@/components/process/ProcessTable'
import customColors from '@/assets/custom-colors'

let PROCESS_NUM = 1

export default {
  components: { ProcessTable },
  data() {
    return {
      customColors: customColors,
      PCB: {
        process_name: null, // 进程名
        process_time: null, // 进程时间片
        process_priority: null, // 进程优先级
        process_status: '就绪', // 状态
        process_all_time: null, // 进程初始所需时间
        process_progress: 100, //
        process_num: 0,
        process_await_time: 0,
        process_response_ratio: 0,
      },
      ready_queue: [],
      over_queue: [],
      options: [
        {
          value: -1,
          label: '请选择调度类型',
        },
        {
          value: 0,
          label: '时间片轮转调度算法',
        },
        {
          value: 1,
          label: '多级反馈队列调度算法',
        },
        {
          value: 2,
          label: '高响应比优先调度算法',
        },
      ],
      value: -1,

      first_queue: [],
      second_queue: [],
      third_queue: [],
      all_queue: [],
    }
  },
  mounted() {},
  computed: {},

  methods: {
    randomCreateProcess() {
      if (this.value === -1) {
        ElMessage({
          showClose: true,
          type: 'error',
          message: '未选择调度类型',
        })
      } else {
        for (let i = 0; i < 5; i++) {
          let pcb = {}
          let maxRand = 30
          pcb.process_time = this.getRandomInt(maxRand)
          pcb.process_all_time = pcb.process_time
          pcb.process_name = Date.parse(new Date())
          pcb.process_priority = this.getRandomInt(maxRand)
          pcb.process_status = '就绪'
          pcb.process_progress = 100
          pcb.process_num = PROCESS_NUM++
          pcb.process_await_time = 0
          this.PCB = pcb
          this.createProcess()
        }
        this.run()
      }
    },

    createProcess() {
      let pcb = JSON.parse(JSON.stringify(this.PCB))
      if (pcb.process_name && pcb.process_time && pcb.process_priority) {
        // console.log('填写成功')
        pcb.process_all_time = pcb.process_time
        this.addToReady(pcb)
        this.PCB.process_name = ''
        this.PCB.process_priority = null
        this.PCB.process_time = null
      } else {
        ElMessage({
          showClose: true,
          type: 'error',
          message: '未填写完整',
        })
      }
    },

    addToReady(process) {
      this.ready_queue.push(process)
    },

    run() {
      this.first_queue = this.ready_queue
      this.all_queue.push(this.first_queue)
      this.all_queue.push(this.second_queue)
      this.all_queue.push(this.third_queue)
      let timer = setInterval(() => {
        if (
          this.ready_queue.length > 0 ||
          this.second_queue.length > 0 ||
          this.third_queue.length > 0
        ) {
          if (this.ready_queue.length > 0)
            this.ready_queue[0].process_status = '执行'
          if (this.value === 0) {
            this.roundRobinDispatch()
          } else if (this.value === 1) {
            if (this.second_queue.length > 0)
              this.second_queue[0].process_status = '执行'
            if (this.third_queue.length > 0)
              this.third_queue[0].process_status = '执行'
            this.first_queue = this.ready_queue
            this.mulFeedDispatch()
          } else if (this.value == 2) {
            this.highRespRatioDispatch()
          }
        } else {
          clearInterval(timer)
        }
      }, 1500)
    },

    roundRobinDispatch() {
      let run_process = this.ready_queue[0]
      run_process.process_time--
      run_process.process_priority--
      run_process.process_progress = parseFloat(
        Number(
          (run_process.process_time / run_process.process_all_time) * 100
        ).toFixed(2)
      )
      let new_process = run_process
      new_process.process_status = '就绪'
      if (run_process.process_time === 0) {
        this.overProcess(run_process)
      } else {
        this.ready_queue.push(new_process)
        this.ready_queue.shift()
        this.ready_queue[0].process_status = '执行'
      }
    },

    mulFeedDispatch() {
      if (this.first_queue.length > 0) {
        this.dispatchProcess(1)
      } else if (this.second_queue.length > 0) {
        this.dispatchProcess(2)
      } else if (this.third_queue.length > 0) {
        this.dispatchProcess(3)
      }
    },

    highRespRatioDispatch() {
      let run_process = this.ready_queue[0]
      run_process.process_time--
      run_process.process_priority--
      run_process.process_progress = parseFloat(
        Number(
          (run_process.process_time / run_process.process_all_time) * 100
        ).toFixed(2)
      )
      let new_process = run_process
      new_process.process_status = '就绪'
      if (run_process.process_time === 0) this.overProcess(run_process)
      this.sortByRespRatio()
    },

    sortByRespRatio() {
      for (let i = 0; i < this.ready_queue.length; i++) {
        let process = this.ready_queue[i]
        process.process_await_time++
        process.process_response_ratio =
          (process.process_await_time + process.process_all_time) /
          process.process_all_time
        // console.log(process)

        process.process_response_ratio = process.process_response_ratio.toFixed(
          2
        )
      }
      this.ready_queue.sort((a, b) => {
        return b.process_response_ratio - a.process_response_ratio
      })
      this.ready_queue[0].process_status = '执行'
    },

    dispatchProcess(time_piece) {
      let cur = time_piece - 1
      let run_process = this.all_queue[cur][0]
      run_process.process_time -= time_piece
      run_process.process_priority--
      run_process.process_progress = parseFloat(
        Number(
          (run_process.process_time / run_process.process_all_time) * 100
        ).toFixed(2)
      )
      if (run_process.process_time === 0) this.overProcess(run_process)
      else if (time_piece < 3) {
        this.all_queue[cur + 1].push(run_process)
        this.all_queue[cur].shift()
      }
    },

    overProcess() {
      let process = this.ready_queue[0]
      process.process_status = '终止'
      this.over_queue.push(process)
      this.ready_queue.shift()
    },

    getRandomInt(max) {
      return Math.floor(Math.random() * max) + 1
    },
  },
}
</script>

<style scoped>
#scheduler {
  width: 95vw;
  margin: 0 auto;
  margin-top: 2vh;
}
.process-card {
  margin-bottom: 1vh;
}
.item {
  margin-left: 10px;
}
</style>
